/*
 * CProgram1.c
 *
 * Created: 5/21/2011 8:26:45 PM
 *  Author: X-Ravin
 */ 
#include "kernel.h"



char preallocProgram(unsigned int flashSize, unsigned int ramSize)
{
	char proc, prog;

	prog = findFreeProgram(flashSize);
	if(prog != ERROR)
	{	
		proc = findFreeProcess(ramSize);
		if(proc != ERROR)
		{
			//At this point we know enough contiguous RAM and FLASH
			//exist for our program.  Now we allocated or reallocate
			//the pointers to get ready for an install.

			allocProgram(prog, flashSize);
			allocProcess(proc, ramSize);
			//Probably only need one of these optimally
			program[prog].PID = proc;
			process[proc].program = prog;

			//Output info
			puts_f(11);
			putchar(prog + 48);
			puts_f(12);
			putchar(proc + 48);
			putchar('\n');
		}
		else 
		{
			puts_f(13);
			return ERROR;
		}
	}
	else puts_f(14);

	return prog;
}




//FLASH based functions **********************************************

char findFreeProgram(unsigned int size)
{
	char i;
	
	for (i = 0; i < NUM_PROCS; i ++)
	{
		if(program[i].state == FREE)
			if(freeFlashSpace(i) > size) return i;
	}
	return ERROR;
}

unsigned int freeFlashSpace(char prog)
{
	char i;
	unsigned int size = 0;
	
	//check if space behind the free program is open
	if(prog != 0)
		size = program[prog].offset_address - (program[prog - 1].offset_address + program[prog - 1].size);
	
	for(i = prog; i < NUM_PROCS; i++)
	{
		if(program[i].state == FREE)
		{
			//First defrag space between procs
			if(i != (NUM_PROCS - 1))
				size += program[i + 1].offset_address - (program[i].offset_address + program[i].size);
			//Then add the freed proc space
			size += program[i].size;
		}
	}
	return size;
}

void allocProgram(char prog, unsigned int size)
{
	program[prog].size = size;
	//Ensure earliest address used to avoid fragging free space.  If prog == 0 then nothing is behind it!
	if(prog != 0)
		program[prog].offset_address = program[prog - 1].offset_address + program[prog - 1].size;
	
	//Defrag next block if free
	if(program[prog + 1].state == FREE)
		program[prog + 1].offset_address = program[prog].offset_address + program[prog].size;
}



void verifyProg(char prog)
{
	unsigned int i;
	for(i = program[prog].offset_address; i < program[prog].offset_address + program[prog].size; i++)
		putchar(pgm_read_byte(i));
}


//SRAM based functions ***********************************************


//Finds lowest PID with enough contiguous free space
char findFreeProcess(unsigned int size)	
{
	char i;
	for(i = 0; i < NUM_PROCS; i++)
	{
		if((process[i].state == FREE) || (process[i].state == FINISHED))
			if(freeRamSpace(i) > size) 
			{
				return i;
			}				
	}
	return ERROR;		
}

//Size = heap space + stack
void allocProcess(char proc, unsigned int size)
{
	process[proc].size = size;
	process[proc].owned_resources = 0;
	
	if(proc != 0)
		process[proc].heap_start_address = process[proc - 1].heap_start_address + process[proc - 1].size;

	if(process[proc + 1].state == FREE)
		process[proc + 1].heap_start_address = process[proc].heap_start_address + process[proc].size;

	process[proc].stack_pointer = process[proc].heap_start_address + process[proc].size;
}

//Given a free PID, finds number of free contiguous bytes up to next PID
unsigned int freeRamSpace(char proc)
{	
	char i;
	unsigned int size = 0;

	if(proc != 0)
		size = process[proc].heap_start_address - (process[proc - 1].heap_start_address + process[proc - 1].size);
	
	for(i = proc; i < NUM_PROCS; i++)
	{
		if((process[i].state == FREE) || (process[i].state == FINISHED))
		{
			//First defrag space between procs
			if(i != (NUM_PROCS - 1))
				size += process[i + 1].heap_start_address - (process[i].heap_start_address + process[i].size);
			//Then add the freed proc space
			size += process[i].size;
		}
	}
	return size;
}

